﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Permissions;
using System.Security.Principal;
using System.Text;
using RentAWorker.Business.Impl.Util;
using RentAWorker.Business.Interfaces;
using Dal = RentAWorker.DataAccess.Interfaces;
using Entities = RentAWorker.DataAccess.Entities;
using RentAWorker.DataAccess.Entities;
using System.ServiceModel.Activation;

namespace RentAWorker.Business.Impl
{
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class ResourceManagementService : IManageResourceService
    {
        private Dal.IResourceAccess ResourceDal;
        private Dal.ILocationAccess LocationDal;

        public ResourceManagementService()
        {
            LocationDal = DataAccessFactory.GetLocationAccess();
            ResourceDal = DataAccessFactory.GetResourceAccess();
        }

        #region IResourceManagementService Members

        [PrincipalPermission(SecurityAction.Demand, Role = "AccountManager")]
        [PrincipalPermission(SecurityAction.Demand, Role = "ResourceManager")]
        public RentAWorker.DataAccess.Entities.RentResource GetResource(int id)
        {
            // Validate all parameters
            if (id < 0) throw new ArgumentException("ID of a resource cannot be negative!");

            // Simply return the resource
            return ResourceDal.GetResource(id);
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "AccountManager")]
        [PrincipalPermission(SecurityAction.Demand, Role = "ResourceManager")]
        public RentAWorker.DataAccess.Entities.RentResource[] GetResourcesByLocation(string location, ResourceType resType)
        {
            // Validate incoming parameters
            Entities.Location Location = null;
            Location = LocationDal.GetLocations(location).FirstOrDefault();
            if (Location == null)
                throw new ArgumentException("Location with the specified name does not exist!");

            // Next get all resources for the specified location
            List<Entities.RentResource> Resources = new List<Entities.RentResource>();
            foreach (var r in ResourceDal.GetResources())
            {
                if ((r.Location != null) && (r.Location.LocationID == Location.LocationID))
                {
                    if ((resType == ResourceType.Machine && r is Machine)
                        || (resType == ResourceType.Worker && r is Worker))
                    {
                        Resources.Add(r);
                    }
                }
            }
            return Resources.ToArray();
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "ResourceManager")]
        public Entities.RentResource SubmitResource(Entities.RentResource resourceToCreate)
        {
            ValidateResource(resourceToCreate);
            Entities.RentResource CreatedResource = ResourceDal.CreateResource(resourceToCreate);
            return CreatedResource;
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "ResourceManager")]
        public void UpdateResource(Entities.RentResource resourceToUpdate)
        {
            ValidateResource(resourceToUpdate);
            ResourceDal.UpdateResource(resourceToUpdate);
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "ResourceManager")]
        public void DeleteResource(int id)
        {
            // Get the resource
            Entities.RentResource Resource = ResourceDal.GetResource(id);
            if (Resource == null) throw new ArgumentException("Resource does not exist!");
            if (Resource.RentalServices.Count > 0) throw new InvalidOperationException("Resource still is requested for services!");

            // Delete the resource if validations succeeded
            ResourceDal.DeleteResource(id);
        }

        #endregion

        #region Private Helper Methods

        private void ValidateResource(Entities.RentResource resourceToCreate)
        {
            // Verify, if a resource with the same name and location exists, already
            var ExistingResources = ResourceDal.GetResources(resourceToCreate.Name);
            if (ExistingResources.Count(r => r.Location.LocationName.Equals(resourceToCreate.Location.LocationName)) > 0)
                throw new ArgumentException("Resource with same name for specified location exists, already!");
        }

        #endregion
    }
}
